﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace MercuryFE
{

    /*
     *  Taken from http://www.orbifold.net/default/?p=187
     *  Customised to have optional corner selectors
     */
    public class ResizingAdorner : Adorner
    {
        // Resizing adorner uses Thumbs for visual elements.
        // The Thumbs have built-in mouse input handling.
        MT topLeft, topRight, bottomLeft, bottomRight;

        // To store and manage the adorner’s visual children.
        VisualCollection visualChildren;

        Rectangle mainrec;

        // Initialize the ResizingAdorner.
        public ResizingAdorner(UIElement adornedElement, bool showTopLeft, bool showTopRight, bool showBottomRight, bool showBottomLeft)
        : base(adornedElement)
        {
            visualChildren = new VisualCollection(this);
            mainrec = new Rectangle();
            SolidColorBrush brush = new SolidColorBrush(Colors.Black);

            mainrec.Stroke = Brushes.Firebrick;
            DoubleCollection col = new DoubleCollection();
            col.Add(5.0);
            col.Add(2.30);
            mainrec.StrokeDashArray = col;
            visualChildren.Add(mainrec);
            // Call a helper method to initialize the Thumbs
            // with a customized cursors.
            if (showTopLeft)
            {
                BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
                bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft);
            }

            if (showTopRight)
            {
                BuildAdornerCorner(ref topRight, Cursors.SizeNESW);
                topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight);
            }

            if (showBottomRight)
            {
                BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE);
                bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight);
            }

            if (showBottomLeft)
            {
                BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW);
                topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft);
            }

        }

        // Handler for resizing from the bottom-right.
        void HandleBottomRight(object sender, DragDeltaEventArgs args)
        {
            FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
            Thumb hitThumb = sender as Thumb;

            if (adornedElement == null || hitThumb == null) return;
                FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;

            // Ensure that the Width and Height are properly initialized after the resize.
            EnforceSize(adornedElement);

            // Change the size by the amount the user drags the mouse, as long as it’s larger
            // than the width or height of an adorner, respectively.
            adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
            adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
        }

        // Handler for resizing from the bottom-left.
        void HandleBottomLeft(object sender, DragDeltaEventArgs args)
        {
            FrameworkElement adornedElement = AdornedElement as FrameworkElement;
            Thumb hitThumb = sender as Thumb;

            if (adornedElement == null || hitThumb == null) return;

            // Ensure that the Width and Height are properly initialized after the resize.
            EnforceSize(adornedElement);

            // Change the size by the amount the user drags the mouse, as long as it’s larger
            // than the width or height of an adorner, respectively.
            adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
            adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
        }

        // Handler for resizing from the top-right.
        void HandleTopRight(object sender, DragDeltaEventArgs args)
        {
            FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
            Thumb hitThumb = sender as Thumb;

            if (adornedElement == null || hitThumb == null) return;
                FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;

            // Ensure that the Width and Height are properly initialized after the resize.
            EnforceSize(adornedElement);

            // Change the size by the amount the user drags the mouse, as long as it’s larger
            // than the width or height of an adorner, respectively.
            adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
            adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
        }

        // Handler for resizing from the top-left.
        void HandleTopLeft(object sender, DragDeltaEventArgs args)
        {
            FrameworkElement adornedElement = AdornedElement as FrameworkElement;
            Thumb hitThumb = sender as Thumb;

            if (adornedElement == null || hitThumb == null) return;

            // Ensure that the Width and Height are properly initialized after the resize.
            EnforceSize(adornedElement);

            // Change the size by the amount the user drags the mouse, as long as it’s larger
            // than the width or height of an adorner, respectively.
            adornedElement.Width = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
            adornedElement.Height = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
        }

        // Arrange the Adorners.
        protected override Size ArrangeOverride(Size finalSize)
        {
            // desiredWidth and desiredHeight are the width and height of the element that’s being adorned.
            // These will be used to place the ResizingAdorner at the corners of the adorned element.
            double desiredWidth = AdornedElement.DesiredSize.Width;
            double desiredHeight = AdornedElement.DesiredSize.Height;
            // adornerWidth & adornerHeight are used for placement as well.
            double adornerWidth = this.DesiredSize.Width;
            double adornerHeight = this.DesiredSize.Height;

            if(topLeft != null) topLeft.Arrange(new Rect(-adornerWidth / 2-5, -adornerHeight / 2-5, adornerWidth, adornerHeight));
            if (topRight != null) topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2 + 5, -adornerHeight / 2 - 5, adornerWidth, adornerHeight));
            if (bottomLeft != null) bottomLeft.Arrange(new Rect(-adornerWidth / 2 - 5, desiredHeight - adornerHeight / 2 + 5, adornerWidth, adornerHeight));
            if (bottomRight != null) bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2 + 5, desiredHeight - adornerHeight / 2 + 5, adornerWidth, adornerHeight));

            mainrec.Width = adornerWidth + 10;
            mainrec.Height = adornerHeight + 10;

            mainrec.Arrange(new Rect(-5, -5, adornerWidth + 10, adornerHeight + 10));

            // Return the final size.
            return finalSize;
        }

        // Helper method to instantiate the corner Thumbs, set the Cursor property,
        // set some appearance properties, and add the elements to the visual tree.
        void BuildAdornerCorner(ref MT cornerThumb, Cursor customizedCursor)
        {
            if (cornerThumb != null) return;

            cornerThumb = new MT();

            // Set some arbitrary visual characteristics.
            cornerThumb.Cursor = customizedCursor;
            cornerThumb.Height = cornerThumb.Width = 10;
            cornerThumb.Opacity = 1.0;
            //cornerThumb.BorderBrush = Brushes.DimGray;
            //cornerThumb.BorderThickness = new Thickness(0.5);

            cornerThumb.Background = new SolidColorBrush(Colors.Orange);

            visualChildren.Add(cornerThumb);
        }

        // This method ensures that the Widths and Heights are initialized. Sizing to content produces
        // Width and Height values of Double.NaN. Because this Adorner explicitly resizes, the Width and Height
        // need to be set first. It also sets the maximum size of the adorned element.
        void EnforceSize(FrameworkElement adornedElement)
        {
            if (adornedElement.Width.Equals(Double.NaN))
                adornedElement.Width = adornedElement.DesiredSize.Width;
            if (adornedElement.Height.Equals(Double.NaN))
                adornedElement.Height = adornedElement.DesiredSize.Height;

            FrameworkElement parent = adornedElement.Parent as FrameworkElement;
            if (parent != null)
            {
                adornedElement.MaxHeight = parent.ActualHeight;
                adornedElement.MaxWidth = parent.ActualWidth;
            }
        }



        // Override the VisualChildrenCount and GetVisualChild properties to interface with
        // the adorner’s visual collection.
        protected override int VisualChildrenCount { get { return visualChildren.Count; } }
        protected override Visual GetVisualChild(int index) { return visualChildren[index]; }

    }

    class MT : Thumb
    {
        protected override Visual GetVisualChild(int index)
        {
        //return base.GetVisualChild(index);
            return null;
        }
        protected override void OnRender(DrawingContext drawingContext)
        {
            //base.OnRender(drawingContext);

            drawingContext.DrawRoundedRectangle(Brushes.Black, new Pen(Brushes.Red, 1), new Rect(this.DesiredSize), 1,1);

        }
    }
}

